package cn.iocoder.yudao.module.trade.order.bo;

import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.validation.Discount;
import cn.iocoder.yudao.framework.validation.Percent;
import cn.iocoder.yudao.module.api.dine.vo.DineConfigVO;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.MemberConfigRespDTO;
import cn.iocoder.yudao.module.api.product.sku.dto.ProductPropertyValueRespDTO;
import cn.iocoder.yudao.module.api.promotion.activity.enums.PromotionTypeEnum;
import cn.iocoder.yudao.module.api.promotion.groupon.dto.GrouponPackageRespDTO;
import cn.iocoder.yudao.module.api.trade.delivery.enums.DeliveryTypeEnum;
import cn.iocoder.yudao.module.api.trade.order.enums.TradeOrderTypeEnum;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nonnull;
import lombok.Data;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 价格计算 Response BO
 * 整体设计，参考 taobao 的技术文档：
 * 1. <a href="https://developer.alibaba.com/docs/doc.htm?treeId=1&articleId=1029&docType=1">订单管理</a>
 * 2. <a href="https://open.taobao.com/docV3.htm?docId=108471&docType=1">常用订单金额说明</a>
 *
 * @author 芋道源码
 */
@Data
public class TradePriceCalculateRespBO {

    /**
     * 店铺编号
     */
    private Long shopId;
    /**
     * 订单类型，枚举 {@link TradeOrderTypeEnum}
     */
    private Integer type;
    /**
     * 支持的配送类型/服务方式数组，枚举 {@link DeliveryTypeEnum}
     */
    private List<Integer> supportDeliveryTypes;

    @Nonnull
    public List<Integer> getSupportDeliveryTypes() {
        if (supportDeliveryTypes == null) {
            supportDeliveryTypes = new ArrayList<>();
        }
        return supportDeliveryTypes;
    }

    /**
     * 订单价格明细
     */
    private Price price;

    @Nonnull
    public Price getPrice() {
        if (price == null) {
            price = new Price();
        }
        return price;
    }

    /**
     * 团购套餐编号
     */
    private Long grouponPackageId;
    /**
     * 团购套餐
     */
    private GrouponPackageRespDTO grouponPackage;

    /**
     * 订单项数组
     */
    private List<OrderItem> items;

    @Nonnull
    public List<OrderItem> getItems() {
        if (items == null) {
            items = new ArrayList<>();
        }
        for (OrderItem item : items) {
            if (item.getWeight() == null) {
                item.setWeight(0d);
            }
            if (item.getDiscountPrice() == null) {
                item.setDiscountPrice(0);
            }
            if (item.getDeliveryPrice() == null) {
                item.setDeliveryPrice(0);
            }
            if (item.getCouponPrice() == null) {
                item.setCouponPrice(0);
            }
            if (item.getVipPrice() == null) {
                item.setVipPrice(0);
            }
            if (item.getWholesalePrice() == null) {
                item.setWholesalePrice(0);
            }
            if (item.getMemberLevelPrice() == null) {
                item.setMemberLevelPrice(0);
            }
            if (item.getPointPrice() == null) {
                item.setPointPrice(0);
            }
            if (item.getDeductPoint() == null) {
                item.setDeductPoint(0);
            }
            if (item.getGivePoint() == null) {
                item.setGivePoint(0);
            }
            if (item.getCryptocurrencyPrice() == null) {
                item.setCryptocurrencyPrice(0);
            }
            if (item.getDeductCryptocurrency() == null) {
                item.setDeductCryptocurrency(0d);
            }
            if (item.getGiveCryptocurrency() == null) {
                item.setGiveCryptocurrency(0d);
            }
            if (item.getGiveBonus() == null) {
                item.setGiveBonus(0d);
            }
        }
        return items;
    }

    /**
     * 营销活动数组，只对应 {@link Price#items} 产品匹配的活动
     */
    private List<Promotion> promotions;

    /**
     * 使用的优惠劵编号
     */
    private Long couponId;
    /**
     * 用户的优惠劵列表（可用 + 不可用）
     */
    private List<Coupon> coupons;

    /**
     * 用户中心配置
     */
    private MemberConfigRespDTO memberConfig;

    /**
     * 点餐配置
     */
    private DineConfigVO dineConfig;
    /**
     * 用餐人数
     */
    private Integer dinePeoples = 1;

    /**
     * 会员是否有效（普通类型+商家类型）
     */
    private Boolean validVip;

    /**
     * 商家类型的会员是否有效
     */
    private Boolean validMerchantVip;

    /**
     * 用户剩余积分
     */
    private Integer totalPoint;
    /**
     * 使用的积分
     */
    private Integer deductPoint;
    /**
     * 赠送的积分
     */
    private Integer givePoint;

    /**
     * 用户剩余联盟豆
     */
    private BigDecimal totalCryptocurrency;
    /**
     * 使用的联盟豆
     */
    private BigDecimal deductCryptocurrency;
    /**
     * 赠送的联盟豆
     */
    private BigDecimal giveCryptocurrency;
    /**
     * 赠送的分红
     */
    private BigDecimal giveBonus;

    /**
     * 首单优惠折扣，10 表示不打折
     */
    @Discount
    private Double firstOrderDiscount = 10d;

    /**
     * 会员优惠折扣，10 表示不打折
     */
    @Discount
    private Double vipDiscount = 10d;

    /**
     * 砍价活动编号
     */
    private Long bargainActivityId;

    /**
     * 是否包邮
     */
    private Boolean freeDelivery;

    /**
     * 赠送的优惠劵
     * key: 优惠劵模板编号
     * value：对应的优惠券数量
     * 目的：用于订单支付后赠送优惠券
     */
    private Map<Long, Integer> giveCouponTemplateCounts;

    /**
     * 订单价格明细
     */
    @Data
    public static class Price {

        /**
         * 产品原价（总计，不包含运费），单位：分，基于 {@link OrderItem#getSkuPrice()} * {@link OrderItem#getCount()} 求和，对应 taobao 的 trade.total_fee 字段
         */
        private int totalPrice;
        /**
         * 产品成本价（总计，不包含运费），单位：分，基于 {@link OrderItem#getSkuCostPrice()} * {@link OrderItem#getCount()} 求和
         */
        private int totalCostPrice;
        /**
         * 产品会员价（总计，不包含运费），单位：分，基于 {@link OrderItem#getSkuVipPrice()} * {@link OrderItem#getCount()} 求和
         */
        private int totalVipPrice;
        /**
         * 产品批发价（总计，不包含运费），单位：分，基于 {@link OrderItem#getSkuWholesaleForRetailPrice()} * {@link OrderItem#getCount()} 求和
         */
        private int totalWholesalePrice;
        /**
         * 所需积分抵扣数（总计），单位：分，基于 {@link OrderItem#getSkuPointDeductCount()} * {@link OrderItem#getCount()} 求和
         */
        private int totalPointDeductCount;
        /**
         * 所需联盟豆抵扣数（总计），单位：分，基于 {@link OrderItem#getSkuCryptocurrencyDeductCount()} * {@link OrderItem#getCount()} 求和
         */
        private int totalCryptocurrencyDeductCount;
        /**
         * 订单优惠（总计），单位：分，对应 taobao 的 order.discount_fee 字段
         */
        private int discountPrice;
        /**
         * 运费金额，单位：分
         */
        private int deliveryPrice;
        /**
         * 优惠劵减免金额（总计），单位：分，对应 taobao 的 trade.coupon_fee 字段
         */
        private int couponPrice;
        /**
         * 团购套餐减免金额（总计），单位：分
         */
        private int grouponPrice;
        /**
         * 积分抵扣的金额，单位：分，对应 taobao 的 trade.point_fee 字段
         */
        private int pointPrice;
        /**
         * 联盟豆抵扣的金额，单位：分
         */
        private int cryptocurrencyPrice;
        /**
         * 会员价减免金额，单位：分
         */
        private int vipPrice;
        /**
         * 批发价减免金额，单位：分
         */
        private int wholesalePrice;
        /**
         * 用户等级减免金额，单位：分
         */
        private int memberLevelPrice;
        /**
         * 最终购买金额（总计），单位：分
         * = {@link #totalPrice}
         * - {@link #couponPrice}
         * - {@link #grouponPrice}
         * - {@link #pointPrice}
         * - {@link #cryptocurrencyPrice}
         * - {@link #discountPrice}
         * + {@link #deliveryPrice}
         * - {@link #vipPrice}
         * - {@link #wholesalePrice}
         * - {@link #memberLevelPrice}
         */
        private int payPrice;

        /**
         * 重置价格
         */
        public Price reset() {
            setTotalPrice(0);
            setTotalCostPrice(0);
            setTotalVipPrice(0);
            setTotalWholesalePrice(0);
            setTotalPointDeductCount(0);
            setTotalCryptocurrencyDeductCount(0);
            setDiscountPrice(0);
            setDeliveryPrice(0);
            setCouponPrice(0);
            setGrouponPrice(0);
            setPointPrice(0);
            setCryptocurrencyPrice(0);
            setVipPrice(0);
            setWholesalePrice(0);
            setMemberLevelPrice(0);
            setPayPrice(0);
            return this;
        }

    }

    /**
     * 订单产品 SKU
     */
    @Data
    public static class OrderItem {

        /**
         * 用于团购套餐等类型的订单，无需订单项
         */
        public static OrderItem empty() {
            // 产品项
            TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem();
            orderItem.setSpuId(0L);
            orderItem.setSkuId(0L);
            orderItem.setCount(0);
            orderItem.setUnitValue(1);
            orderItem.setUnitName("件");
            orderItem.setSelected(false);
            // sku 价格
            orderItem.setSkuPrice(0);
            orderItem.setSkuCostPrice(0);
            orderItem.setSkuVipPrice(0);
            orderItem.setSkuWholesaleForRetailPrice(0);
            orderItem.setSkuPointDeductCount(0);
            orderItem.setSkuCryptocurrencyDeductCount(0);
            orderItem.setPayPrice(0);
            orderItem.setDiscountPrice(0);
            orderItem.setDeliveryPrice(0);
            orderItem.setCouponPrice(0);
            orderItem.setPointPrice(0);
            orderItem.setCryptocurrencyPrice(0);
            orderItem.setVipPrice(0);
            orderItem.setWholesalePrice(0);
            orderItem.setMemberLevelPrice(0);
            // sku 信息
            orderItem.setPicUrl("");
            orderItem.setProperties(null);
            orderItem.setWeight(0D);
            orderItem.setVolume(0D);
            // spu 信息
            orderItem.setSpuName("");
            orderItem.setPlatformCategoryId(0L);
            orderItem.setCategoryId(0L);
            orderItem.setDeliveryTypes(new ArrayList<>());
            orderItem.setDeliveryTemplateId(0L);
            orderItem.setGivePoint(0);
            orderItem.setGiveCryptocurrency(0d);
            orderItem.setGiveBonus(0d);

            // 其他信息
            orderItem.setSupplyName(null);
            orderItem.setSupplyRelatedSkuId(0L);

            return orderItem;
        }

        /**
         * SPU 编号
         */
        private Long spuId;
        /**
         * SKU 编号
         */
        private Long skuId;
        /**
         * 购买数量
         */
        private Integer count;
        /**
         * 计量单位，如：件、份、克
         */
        private String unitName;
        /**
         * 计量数值
         */
        private Integer unitValue;
        /**
         * 购物车项的编号
         */
        private Long cartId;
        /**
         * 是否选中
         */
        private Boolean selected;

        /**
         * 产品原价（单），单位：分
         * 对应 ProductSkuDO 的 price 字段
         * 对应 taobao 的 order.price 字段
         */
        private Integer skuPrice;
        /**
         * 产品成本价（单），单位：分
         * 对应 ProductSkuDO 的 costPrice 字段
         */
        private Integer skuCostPrice;
        /**
         * 产品会员价（单），单位：分
         * 对应 ProductSkuDO 的 vipPrice 字段
         */
        private Integer skuVipPrice;
        /**
         * 厂家零售价（单），单位：分
         * 对应 ProductSkuDO 的 wholesaleForRetailPrice 字段
         */
        private Integer skuWholesaleForRetailPrice;
        /**
         * 产品积分价（单），单位：分
         * 对应 ProductSkuDTO 的 pointDeductCount 字段
         */
        private Integer skuPointDeductCount;
        /**
         * 产品联盟豆价（单），单位：分
         * 对应 ProductSkuDTO 的 cryptocurrencyDeductCount 字段
         */
        private Integer skuCryptocurrencyDeductCount;
        /**
         * 优惠金额（总），单位：分
         * 对应 taobao 的 order.discount_fee 字段
         */
        private Integer discountPrice;
        /**
         * 运费金额（总），单位：分
         */
        private Integer deliveryPrice;
        /**
         * 优惠劵减免金额，单位：分
         * 对应 taobao 的 trade.coupon_fee 字段
         */
        private Integer couponPrice;
        /**
         * 积分抵扣的金额，单位：分
         * 对应 taobao 的 trade.point_fee 字段
         */
        private Integer pointPrice;
        /**
         * 实际使用的积分
         */
        private Integer deductPoint;
        /**
         * 赠送的积分
         */
        private Integer givePoint;
        /**
         * 联盟豆抵扣的金额，单位：分
         */
        private Integer cryptocurrencyPrice;
        /**
         * 实际使用的联盟豆
         */
        private Double deductCryptocurrency;
        /**
         * 赠送的联盟豆
         */
        private Double giveCryptocurrency;
        /**
         * 赠送的分红
         */
        private Double giveBonus;
        /**
         * 会员价减免金额，单位：分
         */
        private Integer vipPrice;
        /**
         * 批发价减免金额，单位：分
         */
        private Integer wholesalePrice;
        /**
         * 用户等级减免金额，单位：分
         */
        private Integer memberLevelPrice;
        /**
         * 应付金额（总），单位：分
         * = {@link #skuPrice} * {@link #count}
         * - {@link #couponPrice}
         * - {@link #pointPrice}
         * - {@link #cryptocurrencyPrice}
         * - {@link #discountPrice}
         * + {@link #deliveryPrice}
         * + {@link #vipPrice} * {@link #count}
         * + {@link #wholesalePrice} * {@link #count}
         * - {@link #memberLevelPrice}
         * 或
         * = {@link #getGrouponPackage()}的相关价格
         */
        private Integer payPrice;

        // ========== 产品 SPU 信息 ==========
        /**
         * 产品名
         */
        private String spuName;
        /**
         * 产品图片，优先级：SKU.picUrl > SPU.picUrl
         */
        private String picUrl;
        /**
         * 行业类目编号
         */
        private Long platformCategoryId;
        /**
         * 产品分类编号
         */
        private Long categoryId;

        // ========== 物流相关字段 =========

        /**
         * 配送类型/服务方式数组，对应 DeliveryTypeEnum 枚举
         */
        private List<Integer> deliveryTypes;

        /**
         * 物流配置模板编号，对应 TradeDeliveryExpressTemplateDO 的 id 编号
         */
        private Long deliveryTemplateId;

        // ========== 产品 SKU 信息 ==========
        /**
         * 产品重量，单位：kg 千克
         */
        private Double weight;
        /**
         * 产品体积，单位：m^3 平米
         */
        private Double volume;

        /**
         * 产品属性数组
         */
        private List<ProductPropertyValueRespDTO> properties;

        /**
         * 供应方名称
         */
        private String supplyName;
        /**
         * 供应方关联SKU编号
         */
        private Long supplyRelatedSkuId;

    }

    /**
     * 营销明细
     */
    @Data
    public static class Promotion {

        /**
         * 营销编号，例如说：营销活动的编号、优惠劵的编号、用户的编号
         */
        private Long id;
        /**
         * 营销名字
         */
        private String name;
        /**
         * 营销类型，枚举 {@link PromotionTypeEnum}
         */
        private Integer type;
        /**
         * 计算时的原价（总），单位：分
         */
        private Integer totalPrice;
        /**
         * 计算时的优惠（总），单位：分
         */
        private Integer discountPrice;
        /**
         * 匹配的产品 SKU 数组
         */
        private List<PromotionItem> items;

        // ========== 匹配情况 ==========

        /**
         * 是否满足优惠条件
         */
        private Boolean match;
        /**
         * 满足条件的提示
         * 如果 {@link #match} = true 满足，则提示“圣诞价:省 150.00 元”
         * 如果 {@link #match} = false 不满足，则提示“购满 85 元，可减 40 元”
         */
        private String description;

    }

    /**
     * 营销匹配的产品 SKU
     */
    @Data
    public static class PromotionItem {

        /**
         * 产品 SKU 编号
         */
        private Long skuId;
        /**
         * 计算时的原价（总），单位：分
         */
        private Integer totalPrice;
        /**
         * 计算时的优惠（总），单位：分
         */
        private Integer discountPrice;

    }

    /**
     * 优惠劵信息
     */
    @Data
    public static class Coupon {

        @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
        private Long id;

        @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送")
        private String name;

        @Schema(description = "发行总量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
        // -1 - 则表示不限制发放数量
        private Integer totalCount;

        @Schema(description = "每人限领个数", requiredMode = Schema.RequiredMode.REQUIRED, example = "66")
        // -1 - 则表示不限制
        private Integer takeLimitCount;

        @Schema(description = "领取方式：1-直接发放、2-指定发放、3-新人券", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
        private Integer takeType;

        @Schema(description = "是否设置满多少金额可用，单位：分，0表示不限制", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
        private Integer usePrice;

        @Schema(description = "生效日期类型：1-固定日期、2-领取日期", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
        private Integer validityType;

        @Schema(description = "生效日期类型为固定日期时的开始时间")
        private LocalDateTime validStartTime;

        @Schema(description = "生效日期类型为固定日期时的结束时间")
        private LocalDateTime validEndTime;

        @Schema(description = "生效日期类型为领取日期的开始天数")
        private Integer fixedStartTerm;

        @Schema(description = "生效日期类型为领取日期的结束天数")
        private Integer fixedEndTerm;

        @Schema(description = "优惠类型：1-折扣，2-减价", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
        private Integer discountType;

        @Schema(description = "优惠类型为折扣时的折扣比例，例如 90 = 90%", example = "90")
        @Percent
        private Integer discountPercent;

        @Schema(description = "优惠类型为折扣时的折扣上限，单位：分", example = "100")
        private Integer discountLimitPrice;

        @Schema(description = "优惠类型为减价时的金额，单位：分", example = "100")
        private Integer discountPrice;

        @Schema(description = "是否可用", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
        private Boolean match;

        @Schema(description = "不可用原因", example = "优惠劵已过期")
        private String mismatchReason;

        @Schema(description = "是否已领取", example = "false")
        @JsonProperty("isReceive")
        private Boolean isReceive;

        @SuppressWarnings("unused")
        public String getUsePriceYuan() {
            return MoneyUtils.fenToYuanStr(NumberUtil.nullToZero(getUsePrice()));
        }

        @SuppressWarnings("unused")
        public String getDiscountLimitPriceYuan() {
            return MoneyUtils.fenToYuanStr(NumberUtil.nullToZero(getDiscountLimitPrice()));
        }

        @SuppressWarnings("unused")
        public String getDiscountPriceYuan() {
            return MoneyUtils.fenToYuanStr(NumberUtil.nullToZero(getDiscountPrice()));
        }

    }

}
